package controllers;

import java.util.List;

import play.*;
import play.mvc.*;
import play.data.*;
import java.util.*;

import models.*;
import views.html.movie.*;
import views.html.application.index;
import static play.data.Form.*;

import play.i18n.*;

import play.libs.Json;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;

import play.Logger;

@With(LogSession.class)
public class MovieManager extends Controller {

    public static Result list(String language) {
		List<Movie> movies = Movie.findAll(language);
        return ok(list.render(movies, Lang.forCode(language)));
    }

    public static Result showToday(String language) {
    	Calendar today = Calendar.getInstance();
		return showByDay(
    				today.get(Calendar.YEAR),
    				today.get(Calendar.MONTH) + 1,
    				today.get(Calendar.DATE),
					language
    	);
    }

    public static Result showByDay(int year, int month, int day, String language) {
		Calendar cal = Calendar.getInstance();
		Date today = cal.getTime();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month-1);
		cal.set(Calendar.DATE, day);
		Date selectedDate = cal.getTime();
		int result = selectedDate.compareTo(today);
		if ( result < 0) {
			return redirect(routes.MovieManager.showToday(language));
		} else {
			List<Movie> movies = Movie.findByDate(year, month, day, language);
			return ok(show.render(movies, day+"-"+month+"-"+year, Lang.forCode(language)));
		}
    }

    public static Result detail(Long id, String language) {
    	List<Movie> movies = Movie.findAll(language);
		Movie m = Movie.findById(id, language);

		if(m == null){
			return notFound();
		} else {
    		return ok(movie.render(movies, m, m.sessions, true, Lang.forCode(language)));
    	}
    }

    public static Result session(Long id, String language){
    	MovieSession session = MovieSession.findById(id, language);
    	if(session().containsKey("uuid")) {
			String uuid = session("uuid");
			String username = LogSession.getUsernameFromUUID(uuid);
			if(username != null){
			return ok(house.render(session, form(SeatForm.class), Lang.forCode(language)));
			}
		}

		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.HOUR, 11);
		cal.set(Calendar.MINUTE, 59);
		cal.set(Calendar.SECOND, 59);
		cal.set(Calendar.AM_PM, Calendar.PM);
		Date deadline = cal.getTime();
		if(session.showtime.getTime() > deadline.getTime()){
			flash("public", "movie.session.permission");
			return redirect(routes.MovieManager.detail(session.movie.id, language));
		} else {
			return ok(house.render(session, form(SeatForm.class), Lang.forCode(language)));
		}
    }

    public static Result payment(){
		Form<SeatForm> seatForm = form(SeatForm.class).bindFromRequest();

		if(seatForm.hasErrors()) {
			return internalServerError("Oops");//badRequest(register.render(registerForm, Lang.forCode("zh")));
		} else {
			Long id = seatForm.get().session;
			String language = seatForm.get().language;
			String[] seat = seatForm.get().seats.split(":");
			int bypassLogin = seatForm.get().bypassLogin;
			MovieSession session = MovieSession.findById(id, language);

			String uuid = session("uuid");
			String username = LogSession.getUsernameFromUUID(uuid);

			if (username != null || bypassLogin == 1) {
				boolean test = OnHold.startHolding(id,seat);
				if (username != null)
				{
					User user = User.findByUser(username);
					Form<PaymentForm> paymentForm = form(PaymentForm.class);

					PaymentForm userdata = new PaymentForm();
					userdata.email = user.email;
					userdata.credit_card = user.credit_card;

					paymentForm = paymentForm.fill(userdata);

					return ok(payment.render(session, paymentForm, seat, user, Lang.forCode(language)));
				}
				return ok(payment.render(session, form(PaymentForm.class), seat, null, Lang.forCode(language)));

			}

			return ok(paymentLogin.render( form(PaymentLoginForm.class), session, seat, Lang.forCode(language)));
    	}
    }

	public static Result paymentLogin(){
		Form<PaymentLoginForm> paymentLoginForm = form(PaymentLoginForm.class).bindFromRequest();

		Long id = Long.parseLong( paymentLoginForm.field("session").value() );
		String language = paymentLoginForm.field("language").value();
		String[] seat = paymentLoginForm.field("seats").value().split(":");
		MovieSession session = MovieSession.findById(id, language);

		if(paymentLoginForm.hasErrors()) {
			return badRequest(paymentLogin.render(paymentLoginForm, session, seat, Lang.forCode(language)));
		} else {
			User user = User.findByUser(paymentLoginForm.get().username);
			String uuid = LogSession.createSession(user.username, user.role);
			session("uuid", uuid);
			Http.Context.current().args.put("username",user.username);
			return payment();
		}
	}


    public static Result confirm(){
		Form<PaymentForm> paymentForm = form(PaymentForm.class).bindFromRequest();

		Long session = Long.parseLong(paymentForm.field("session").value());
		String[] seats = paymentForm.field("seats").value().split(":");
		String lang = paymentForm.field("lang").value();

		if(lang == null)
			lang = "en";


		if(paymentForm.hasErrors()) {
			//OnHold.endHolding(session,seats);

			String uuid = session("uuid");
			String username = LogSession.getUsernameFromUUID(uuid);
			User user = null;

			MovieSession movieSession = MovieSession.findById(session,lang);

			if(username!=null)
				user = User.findByUser(username);

			return badRequest(payment.render(movieSession, paymentForm, seats, user, Lang.forCode(lang)));
		} else {

			String email = paymentForm.get().email;
			String credit_card = paymentForm.get().credit_card;

			int points = paymentForm.get().points;

			String username = null;

			if(session().containsKey("uuid")) {
				String uuid = session("uuid");
				username = LogSession.getUsernameFromUUID(uuid);
			}

			/*

			Logger.info("Session:" + session);
			Logger.info(paymentForm.get().seats);

			int count = 0;
			List<OnHold> records = OnHold.findBySession(session);
			for(OnHold record : records){
				Logger.info(record.seat_no);
				if(Arrays.asList(seats).contains(new String(record.seat_no))){
					count++;
				}
			}

			Logger.info("count:" + count);
			Logger.info("seats:" + seats.length);

			*/



			int count = seats.length; // For temporay

			if(count == seats.length){
				for(int i=0;i<seats.length;i++){
					if(points>0)
						new Payment(session, seats[i], email, credit_card, username, 4).save();
					else
						new Payment(session, seats[i], email, credit_card, username, 0).save();
				}
				OnHold.endHolding(session,seats);

				//Loyalty Point Accumulation
				if(username!=null && points==0) {
					User user = User.findByUser(username);
					MovieSession movieSession = MovieSession.findById(session, "en");
					user.points += ((movieSession.price*seats.length)/10);
					user.save();
				}

				//Loyalty Point Reducation
				if(username!=null && points>0) {
					User user = User.findByUser(username);
					user.points -= points;
					user.save();
				}

				flash("payment","movie.payment.success");
	    		return redirect(routes.Application.index(lang));
	    	} else {
		    	return internalServerError("Payment Error");
	    	}
    	}
    }

    @BodyParser.Of(BodyParser.Json.class)
    public static Result checkAvailableSeat(Long id){
    	JsonNode json = request().body().asJson();
    	ObjectNode result = Json.newObject();

		List<OnHold> hold_records = OnHold.findBySession(id);
		List<Payment> sold_records = Payment.findBySession(id);

		List<UnavailableSeat> unavailable_records = UnavailableSeat.findByHouse(MovieSession.find.byId(id).house.id);

    	String[] hold = new String[hold_records.size()];
    	String[] sold = new String[sold_records.size()];

    	String[] unavailable = new String[unavailable_records.size()];

    	for(int i=0;i<hold_records.size();i++){
	    	hold[i] = hold_records.get(i).seat_no;
    	}
    	for(int i=0;i<sold_records.size();i++){
	    	sold[i] = sold_records.get(i).seat_no;
    	}

    	for(int i=0;i<unavailable_records.size();i++){
	    	unavailable[i] = unavailable_records.get(i).seat_no;
    	}

    	result.put("hold", Json.toJson(hold));
    	result.put("sold", Json.toJson(sold));
    	result.put("unavailable", Json.toJson(unavailable));

    	return ok(result);
    }
}
